import time,datetime,json
import pandas as pd
from 组件.notice import show_notification_thread
from 组件.sqlite import SimpleSQLite
from 公共函数 import get_stock,need_notice,add_notice,update_notice
from 基础配置 import settings

stock_span = {stock["all_code"]: stock["span"] for stock in settings.STOCK_CODE}
stock_down = {stock["all_code"]: stock["down"] for stock in settings.STOCK_CODE}
day_look = settings.DAY_LOOK
from xtquant import xtdata
xtdata.enable_hello = False
from 指标.MACD import MACDSignalCalculator, MACDConfig

# 全局缓存：避免频繁计算MACD
_macd_cache = {}
_cache_timestamp = {}
_CACHE_TTL = 60  # 缓存有效期：60秒
_order_last_check = {}  # 记录每个订单上次检测时间
_ORDER_CHECK_INTERVAL = 10  # 订单检测间隔：10秒
_order_max_price = {}  # 记录每个订单的最高价格 {order_sysid: max_price}

def is_after_12pm():
    """判断上午或者下午,如果day_look小于3,那11点开始就使用午盘规则"""
    now = datetime.datetime.now().time()  # 获取当前时间（只取时间部分）
    if day_look<=3:
        noon = datetime.time(12, 0, 0)  # 创建12点的时间对象
    else:
        noon = datetime.time(12, 0, 0)  # 创建12点的时间对象
    return now > noon

def check_macd_in_bearish_zone(stock_code):
    """
    检测当前MACD是否处于空头区域（绿柱状态）- 实时状态检测
    
    Args:
        stock_code: 股票代码
    
    Returns:
        bool: True表示当前为绿柱（DIFF < DEA），应该止损；False表示为红柱或无数据
    
    说明:
        这是状态检测，而非信号检测：
        - 红柱（DIFF > DEA）：多头状态，不止损
        - 绿柱（DIFF < DEA）：空头状态，立即止损 ✅
        
        与死叉信号的区别：
        - 死叉信号：DIFF下穿DEA的那一刻（只有一个点）
        - 绿柱状态：DIFF在DEA下方的持续时间（可能很长）
    """
    try:
        current_time = time.time()
        cache_key = f"macd_state_{stock_code}"
        
        # 检查缓存是否有效（60秒内）
        if cache_key in _cache_timestamp:
            if current_time - _cache_timestamp[cache_key] < _CACHE_TTL:
                # 使用缓存的MACD状态
                cached_result = _macd_cache.get(cache_key, {})
                if cached_result:
                    is_bearish = cached_result.get('is_bearish', False)
                    cached_diff = cached_result.get('diff', 0)
                    cached_dea = cached_result.get('dea', 0)
                    cached_macd = cached_result.get('macd', 0)
                    
                    # 输出缓存状态（调试用）
                    status = "绿柱" if is_bearish else "红柱"
                    print(f"📦 {stock_code} 使用缓存: {status} (DIFF={cached_diff:.6f}, DEA={cached_dea:.6f})")
                    return is_bearish
        
        # 缓存过期或不存在，重新计算
        calculator = MACDSignalCalculator(xtdata, use_warmup=False)
        
        # 获取当日tick数据
        ticks = calculator.get_segment_ticks(stock_code)
        if not ticks or stock_code not in ticks:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = {'is_bearish': False}
            return False
        
        df = ticks[stock_code]
        if df.empty:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = {'is_bearish': False}
            return False
        
        # 确定价格列和时间列
        price_col = next((col for col in ['price', 'lastPrice', 'close', 'last', 'current'] 
                         if col in df.columns), None)
        time_col = next((col for col in df.columns if 'time' in col.lower()), None)
        
        if not price_col or not time_col:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = {'is_bearish': False}
            return False
        
        # 转换时间戳
        if df[time_col].dtype in ['int64', 'float64']:
            df['time'] = pd.to_datetime(df[time_col], unit='ms') + pd.Timedelta(hours=8)
        else:
            df['time'] = pd.to_datetime(df[time_col], format='%Y%m%d%H%M%S', errors='coerce')
        
        df = df[df['time'].notna()].sort_values('time')
        df_filtered = df[df[price_col] > 0].copy()
        
        if df_filtered.empty:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = {'is_bearish': False}
            return False
        
        # 过滤交易时间
        df_filtered['time_only'] = df_filtered['time'].dt.time
        morning_start = pd.Timestamp('09:30:00').time()
        morning_end = pd.Timestamp('11:30:00').time()
        afternoon_start = pd.Timestamp('13:00:00').time()
        afternoon_end = pd.Timestamp('15:00:00').time()
        
        df_filtered = df_filtered[
            ((df_filtered['time_only'] >= morning_start) & (df_filtered['time_only'] <= morning_end)) |
            ((df_filtered['time_only'] >= afternoon_start) & (df_filtered['time_only'] <= afternoon_end))
        ]
        
        if df_filtered.empty:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = {'is_bearish': False}
            return False
        
        # 重新采样为分钟数据
        df_minutes = calculator.resample_ticks_to_minutes(df_filtered, price_col)
        if df_minutes.empty:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = {'is_bearish': False}
            return False
        
        # 计算MACD
        diff, dea, macd_histogram = calculator.calculate_macd_experimental(
            df_minutes['close'],
            fast=MACDConfig.FAST_EMA,
            slow=MACDConfig.SLOW_EMA,
            signal=MACDConfig.SIGNAL_EMA,
            experiment_mode='A',
            verbose=False
        )
        
        # 获取最新的MACD值
        if len(diff) == 0 or len(dea) == 0:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = {'is_bearish': False}
            return False
        
        latest_diff = diff.iloc[-1]
        latest_dea = dea.iloc[-1]
        latest_macd = macd_histogram.iloc[-1] if len(macd_histogram) > 0 else 0
        
        # 判断是否为绿柱（空头）：DIFF < DEA
        # 注意：MACD柱 = 2*(DIFF-DEA)，所以DIFF<DEA等价于MACD<0
        is_bearish = (latest_diff < latest_dea)
        
        # 缓存结果
        _cache_timestamp[cache_key] = current_time
        _macd_cache[cache_key] = {
            'is_bearish': is_bearish,
            'diff': float(latest_diff),
            'dea': float(latest_dea),
            'macd': float(latest_macd)
        }
        
        # 详细的调试输出
        if is_bearish:
            print(f"🟢 {stock_code} 当前MACD为【绿柱】（空头状态）")
            print(f"   └─ DIFF={latest_diff:.6f} < DEA={latest_dea:.6f}")
            print(f"   └─ MACD柱={latest_macd:.6f} (应该<0)")
        else:
            print(f"🔴 {stock_code} 当前MACD为【红柱】（多头状态）")
            print(f"   └─ DIFF={latest_diff:.6f} > DEA={latest_dea:.6f}")
            print(f"   └─ MACD柱={latest_macd:.6f} (应该>0)")
        
        return is_bearish
        
    except Exception as e:
        print(f"检测MACD状态异常: {e}")
        # 异常时也更新缓存，避免频繁重试
        _cache_timestamp[f"macd_state_{stock_code}"] = time.time()
        _macd_cache[f"macd_state_{stock_code}"] = {'is_bearish': False}
        return False

def check_macd_red_bar_decline(stock_code, decline_count=3):
    """
    检测MACD红柱是否连续N根下跌（带缓存优化）
    
    Args:
        stock_code: 股票代码
        decline_count: 连续下跌的柱数，默认3根
    
    Returns:
        bool: True表示红柱连续下跌，False表示未连续下跌
    
    注意：缓存时间很短(10秒)以保证实时性，避免止损延迟
    """
    try:
        current_time = time.time()
        cache_key = f"red_bar_decline_{stock_code}"
        
        # 检查缓存是否有效（10秒内） - 缩短缓存时间保证实时性
        RED_BAR_CACHE_TTL = 10  # 从60秒改为10秒
        if cache_key in _cache_timestamp:
            if current_time - _cache_timestamp[cache_key] < RED_BAR_CACHE_TTL:
                # 使用缓存结果
                cached_result = _macd_cache.get(cache_key, False)
                print(f"[缓存] {stock_code} 红柱下跌检测: {cached_result}")
                return cached_result
        
        # 缓存过期或不存在，重新计算
        calculator = MACDSignalCalculator(xtdata, use_warmup=False)
        
        # 获取当日tick数据
        ticks = calculator.get_segment_ticks(stock_code)
        if not ticks or stock_code not in ticks:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = False
            return False
        
        df = ticks[stock_code]
        if df.empty:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = False
            return False
        
        # 确定价格列和时间列
        price_col = next((col for col in ['price', 'lastPrice', 'close', 'last', 'current'] 
                         if col in df.columns), None)
        time_col = next((col for col in df.columns if 'time' in col.lower()), None)
        
        if not price_col or not time_col:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = False
            return False
        
        # 转换时间戳
        if df[time_col].dtype in ['int64', 'float64']:
            df['time'] = pd.to_datetime(df[time_col], unit='ms') + pd.Timedelta(hours=8)
        else:
            df['time'] = pd.to_datetime(df[time_col], format='%Y%m%d%H%M%S', errors='coerce')
        
        df = df[df['time'].notna()].sort_values('time')
        df_filtered = df[df[price_col] > 0].copy()
        
        if df_filtered.empty:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = False
            return False
        
        # 过滤交易时间
        df_filtered['time_only'] = df_filtered['time'].dt.time
        morning_start = pd.Timestamp('09:30:00').time()
        morning_end = pd.Timestamp('11:30:00').time()
        afternoon_start = pd.Timestamp('13:00:00').time()
        afternoon_end = pd.Timestamp('15:00:00').time()
        
        df_filtered = df_filtered[
            ((df_filtered['time_only'] >= morning_start) & (df_filtered['time_only'] <= morning_end)) |
            ((df_filtered['time_only'] >= afternoon_start) & (df_filtered['time_only'] <= afternoon_end))
        ]
        
        if df_filtered.empty:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = False
            return False
        
        # 重新采样为分钟数据
        df_minutes = calculator.resample_ticks_to_minutes(df_filtered, price_col)
        if df_minutes.empty or len(df_minutes) < decline_count + 1:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = False
            return False
        
        # 计算MACD
        diff, dea, macd_histogram = calculator.calculate_macd_experimental(
            df_minutes['close'],
            fast=MACDConfig.FAST_EMA,
            slow=MACDConfig.SLOW_EMA,
            signal=MACDConfig.SIGNAL_EMA,
            experiment_mode='A',
            verbose=False
        )
        
        # 检查MACD柱状图（红柱：MACD > 0）
        # 获取最后N根柱子
        if len(macd_histogram) < decline_count + 1:
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = False
            return False
        
        last_bars = macd_histogram.tail(decline_count + 1)
        
        # 检查是否都是红柱（大于0）
        if not all(last_bars > 0):
            _cache_timestamp[cache_key] = current_time
            _macd_cache[cache_key] = False
            return False
        
        # 检查是否连续下跌
        is_declining = True
        for i in range(len(last_bars) - 1):
            if last_bars.iloc[i+1] >= last_bars.iloc[i]:
                is_declining = False
                break
        
        # 更新缓存
        _cache_timestamp[cache_key] = current_time
        _macd_cache[cache_key] = is_declining
        
        if is_declining:
            print(f"✅ [实时检测] {stock_code} MACD红柱连续{decline_count}根下跌")
            print(f"   最近{decline_count+1}根柱值: {last_bars.values}")
            return True
        else:
            print(f"⚪ [实时检测] {stock_code} 红柱未连续下跌")
            print(f"   最近{decline_count+1}根柱值: {last_bars.values}")
            return False
        
    except Exception as e:
        print(f"检测MACD红柱下跌异常: {e}")
        # 异常时也更新缓存，避免频繁重试
        _cache_timestamp[f"red_bar_decline_{stock_code}"] = time.time()
        _macd_cache[f"red_bar_decline_{stock_code}"] = False
        return False

def order_watch(self):

    ##撤单检测
    notice = False
    filled_orders_sorted, no_filled_orders, stocks = self.get_orders()  # 修改这里，接收3个返回值
    print("未成交挂单检测运行中......")
    for order in no_filled_orders:
        stock_code = order.stock_code
        msg = f"订单 {order.order_sysid}"
        if stock_code == "000838.SZ":
            continue
        if stock_code == "159612.SZ":
            continue
        if stock_code == "513130.SH":
            continue

        if order.order_type == 23:
            # 检测n分钟没买入撤销
            n = 10
            current_time = datetime.datetime.now().timestamp()  # 当前时间戳
            time_diff = current_time - order.order_time  # 计算时间差（秒）

            if time_diff > n:
                print(f"{stock_code}检测{n}秒没买入撤销挂单")
                ##这里需要拿到remark判断level是否是0，0才会提高一挡位买
                remark_str = order.order_remark
                try:
                    remark = json.loads(remark_str)
                    level = remark.get("level", 1)
                    if level == 100:
                        print(f"{stock_code}检测{n}秒没买入高一级别买入")
                        new_price = float(order.price) + 0.001
                        new_remark = {
                            "level": 1,
                            "macd": remark.get("macd", ""),
                            "rsi": remark.get("rsi", ""),
                            "atr": remark.get("atr", ""),
                        }
                        new_remark_string = json.dumps(new_remark, ensure_ascii=False)

                        self.mod_order_price(order.order_sysid, new_price,new_remark_string)
                except json.JSONDecodeError as e:
                    pass
                except KeyError as e:
                    pass
                self.cancel_order(order.order_sysid)
        else:
            ##新增一个,挂单时间超过当前1分钟才监测止损
            current_time = datetime.datetime.now().timestamp()  # 当前时间戳
            time_diff = current_time - order.order_time  # 计算时间差（秒）
            if time_diff < 60:
                print(f"订单 {order.order_sysid} 挂单时间不足1分钟({time_diff:.1f}秒)，跳过止损检测")
                continue


            ##检测5分钟没卖出则下降一档卖出
            span = stock_span.get(stock_code)
            current_time = datetime.datetime.now().timestamp()  # 当前时间戳
            time_diff = current_time - order.order_time  # 计算时间差（秒）
            # if time_diff > 300:
            #     new_price = float(order.price) - float(span)
            #     print(f"{stock_code}检测5分钟没卖出则下降一档卖出")
            #     self.mod_order_price(order.order_sysid,new_price)

            ##新的方案，分两笔买入，一开始第一笔止损和第二笔止损的都是固定的。
            ##默认都给3挡,如果触达3档全部止损
            ##1.获取当前价格,如果有问题需要去除使用xtdata
            current_price = get_last_price(xtdata,stock_code)
            if current_price>0:
                now_price = current_price
            else:
                data = get_stock(stock_code)
                now_price = data["now_price"]
            print(f"订单 {order.order_sysid}挂单价格{order.price},检测最新迅投价格 {current_price},检测最新本地价格 {now_price}")
            ##获取订单order_remark信息
            remark_str = order.order_remark
            buy_id = 0
            sell_type = 1
            order_type = 1
            buy_price = 0
            down_price = 0
            # print(remark_str)

            try:
                remark = json.loads(remark_str)
                buy_id = remark.get("buy_id", 0)
                sell_type = remark.get("sell_type", 1)
                order_type = remark.get("order_type", 1)
                buy_price = remark.get("buy_price", 0)

                print(f"买入价格:{buy_price}")
            except json.JSONDecodeError as e:
                pass
            except KeyError as e:
                pass

            buy_id = 1

            if buy_id:

                if sell_type==1:##1为普通单2为区间单
                    ##测算这笔挂单之后的价格，如果达到了0.3%的高度，则止损价格直接就是买入价格
                    order_key = order.order_sysid
                    
                    # 初始化或更新最高价格
                    if order_key not in _order_max_price:
                        _order_max_price[order_key] = float(now_price)
                        print(f"订单 {order_key} 初始化最高价格: {now_price}")
                    else:
                        if float(now_price) > _order_max_price[order_key]:
                            old_max = _order_max_price[order_key]
                            _order_max_price[order_key] = float(now_price)
                            print(f"订单 {order_key} 更新最高价格: {old_max} -> {now_price}")
                    
                    # 计算涨幅
                    max_price = _order_max_price[order_key]
                    price_increase_ratio = (max_price - float(buy_price)) / float(buy_price)
                    
                    # 如果涨幅达到0.3%，止损价格设为买入价格（保本）
                    # if price_increase_ratio >= 0.003:
                    #     down_price = float(buy_price)
                    #     print(f"订单 {order_key} 涨幅已达到{price_increase_ratio*100:.2f}%，启用保本止损(止损价={buy_price})")
                    # else:
                    #     down_price = float(buy_price) - float(span * 10)
                    #     print(f"订单 {order_key} 当前涨幅{price_increase_ratio*100:.2f}%，使用常规止损(止损价={down_price:.3f})")
                if sell_type==2:
                    down_price = float(buy_price) - float(span * 3)

                ##跌破1%止损（实时检测，每秒都执行）
                if float(now_price) <= float(down_price):
                    notice = True
                    msg += "跌幅警告,"
                    print(f"平仓订单 {order.order_sysid}买入价格{buy_price},最新价格 {now_price}止损{down_price}")
                    self.modify_to_market_order(order.order_sysid)
                
                # MACD相关止损检测（带间隔控制，避免频繁检测）
                current_time = time.time()
                order_check_key = f"{order.order_sysid}_{stock_code}"
                last_check_time = _order_last_check.get(order_check_key, 0)
                
                # 只有距离上次检测超过指定间隔时才执行MACD检测
                if current_time - last_check_time >= _ORDER_CHECK_INTERVAL:
                    _order_last_check[order_check_key] = current_time
                    
                    ##MACD绿柱止损：检测当前MACD是否为绿柱（空头状态）
                    if sell_type==1 or sell_type==2:
                        try:
                            # 只要当前MACD柱为绿色（DIFF < DEA），就立即止损
                            if check_macd_in_bearish_zone(stock_code):
                                notice = True
                                msg += "MACD绿柱止损,"
                                print(f"平仓订单 {order.order_sysid}检测到MACD绿柱（空头），执行止损")
                                self.modify_to_market_order(order.order_sysid)
                        except Exception as e:
                            print(f"MACD绿柱止损检测异常: {e}")
                    
                    ##macd红柱连续两根下跌止损，检测是否连续2根红柱下跌
                    try:
                        if check_macd_red_bar_decline(stock_code, decline_count=3):
                            notice = True
                            msg += "MACD红柱连续下跌止损,"
                            print(f"平仓订单 {order.order_sysid}检测到MACD红柱连续下跌,执行止损")
                            self.modify_to_market_order(order.order_sysid)
                    except Exception as e:
                        print(f"MACD红柱止损检测异常: {e}")

            else:
                # 当buy_id为0或无效时，使用默认止损逻辑
                # 这里可以根据需要添加默认的止损策略
                print(f"订单 {order.order_sysid} 缺少有效的buy_id信息，跳过止损检查")

        # 在循环外部统一处理通知逻辑
        if notice:
            need = need_notice(order.order_sysid,msg)
            if need ==0:
                add_notice(order.order_sysid,msg)
            if need==1:
                print(msg)
                update_notice(order.order_sysid,msg)
                # show_notification_thread("撤单提醒", msg)
        else:
            print("挂单检测正常")

def get_last_price(xtdata,stock_code):
    start_time = time.time()  # 记录开始时间
    current_price = 0
    # 获取最新tick数据
    tick_data = xtdata.get_full_tick([stock_code])
    # 安全地获取价格数据
    if stock_code in tick_data:
        stock_data = tick_data[stock_code]
        # 检查数据结构并安全获取价格
        if isinstance(stock_data, dict):
            # 如果返回的是字典格式
            current_price = stock_data.get('lastPrice', 0)
        elif isinstance(stock_data, list) and len(stock_data) > 0:
            # 如果返回的是列表格式
            if isinstance(stock_data[0], dict):
                current_price = stock_data[0].get('lastPrice', 0)
            else:
                current_price = stock_data[0] if stock_data[0] else 0
    
    end_time = time.time()  # 记录结束时间
    execution_time = (end_time - start_time) * 1000  # 转换为毫秒
    print(f"get_last_price 执行时间: {execution_time:.2f} 毫秒")
    return current_price

def check_other_order_filled(filled_orders, buy_id, current_order_sysid):
    try:
        # 查找相同buy_id的其他已成交订单
        for order in filled_orders:
            if order.order_sysid == current_order_sysid:
                continue  # 跳过当前订单
                
            try:
                # 解析订单备注信息
                remark_str = order.order_remark
                if remark_str:
                    remark = json.loads(remark_str)
                    order_buy_id = remark.get("buy_id")
                    
                    # 如果找到相同buy_id的订单且已成交
                    if order_buy_id == buy_id:
                        print(f"找到相同buy_id {buy_id} 的订单 {order.order_sysid} 已成交")
                        return True
            except (json.JSONDecodeError, KeyError) as e:
                # 如果解析备注失败，跳过这个订单
                continue
                
        print(f"未找到相同buy_id {buy_id} 的其他已成交订单")
        return False
        
    except Exception as e:
        print(f"查询相同buy_id订单时出错: {e}")
        return False

if __name__ == "__main__":
    price = get_last_price(xtdata,stock_code="513310.SH")
    print(price)